#include "GameFieldFrame.h"

//meaning of the map numbers:
//0: food
//1: wall
//2: ghost
//3: pacman
//4: portal/teleporter
//5: empty field
//6: cherry bonus
//7: eating ghosts bonus

GameFieldFrame::GameFieldFrame()
{
	m_iLevelNumber = 1;
	width=0;
	twoPlayerMode=true;
	wolfenstein3dMode = false;
	counterLight=0;
	macieksbool=false;
}

GameFieldFrame::~GameFieldFrame()
{
	for(unsigned int i = 0; i < frames.size(); i++)
	{
		delete frames.at(i);
	}

	for(unsigned int i = 0; i < ghosts.size(); i++)
	{
		delete ghosts.at(i);
	}
}

HRESULT GameFieldFrame::Init(int level, CZenKeyboard *Keyboard )
{
LPDIRECT3DSURFACE8 m_pYouBeat;
	m_numberFood = 0;
	width=0;
	m_iLevelNumber = level;
	//load the objects
	HRESULT res;
	res = m_Wall.LoadXFile("res/wall.X");
	if (FAILED(res))
	{
		::MessageBox(NULL,"Failed to load wall.X", "Error", 0);
		return E_FAIL;
	}
	res = m_Floor.LoadXFile("res/floor.X");
	if (FAILED(res))
	{
		::MessageBox(NULL,"Failed to load floor.X", "Error", 0);
		return E_FAIL;
	}
	res = m_Food.LoadXFile("res/sfere.X");
	if (FAILED(res))
	{
		::MessageBox(NULL,"Failed to load sfere.X", "Error", 0);
		return E_FAIL;
	}

	res = m_Teleporter.LoadXFile("res/teleport.X");
	if (FAILED(res))
	{
		::MessageBox(NULL,"Failed to load teleport.X", "Error", 0);
		return E_FAIL;
	}
	res = m_Cherry.LoadXFile("res/cherry.X");
	if (FAILED(res))
	{
		::MessageBox(NULL,"Failed to load cherry.X", "Error", 0);
		return E_FAIL;
	}
	res = m_SuperSfere.LoadXFile("res/supersfere.X");
	if (FAILED(res))
	{
		::MessageBox(NULL,"Failed to load supersfere.X", "Error", 0);
		return E_FAIL;
	}
	//read a file for the map layout
	string line;
	string mapLocation = "res/levels/level";
	ostringstream oss;
	oss << mapLocation << m_iLevelNumber;
	mapLocation = oss.str();
	mapLocation += ".map";
	ifstream myfile (mapLocation.c_str());
	map.clear();
	row.clear();
	if (myfile.is_open())
	{
		while (! myfile.eof() )
		{
			++width;
			getline (myfile,line);
			char * temp = new char[line.length()+1];
			strcpy(temp, line.c_str());
			for(unsigned int i = 0; i < line.length(); i++)
			{
				char number = temp[i];
				row.push_back((int)atoi(&number));
			}
			map.push_back(row);
			row.clear();
		}
		length=line.length();
		myfile.close();
	}
	else 
	{
		//::MessageBox( NULL,"You beat the game!", "Congratulations", 0);
	if(m_Sound->isPlayingBackground()){
		m_Sound->StopBackgroundMusic();
		}
		m_Sound->LoadZenSound("res/soundeffects/win.wav");
		m_Sound->PlayZenSound();
		
		zen->m_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,255,255), 1.0f, 0 );
		zen->LoadBitmapToSurface("res/youbeat.bmp", &m_pYouBeat, zen->m_pDevice);
		zen->CopySurfaceToSurface(0, m_pYouBeat, 0, zen->m_pBackSurface, FALSE, D3DCOLOR_ARGB(0,0,0,0));
		zen->m_pDevice->BeginScene();
		zen->m_pBackSurface->UnlockRect();	
		zen->m_pDevice->Present( NULL, NULL, NULL, NULL );

		Sleep ( 5500);	

		return E_FAIL;
	}

	//reverse order of lines in newly loaded map
	//so that what we see in game matches to what we see in *.map file
	for(int i=0; i<width/2;i++)
		for(int j=0; j<length;j++)
		{
			int tmp=map.at(i).at(j);
			map.at(i).at(j)=map.at(width-1-i).at(j);
			map.at(width-1-i).at(j)=tmp;
		}
	////


	//create the frames from the map
	for (int i = 0; i < frames.size(); i++)
	{
		delete frames.at(i);
	}
	frames.clear();
	for (int i = 0; i < ghosts.size(); i++)
	{
		delete ghosts.at(i);
	}
	ghosts.clear();
	for (unsigned int i = 0; i < map.size(); i++)
	{
		row = map.at(i);
		for(unsigned int j = 0; j < row.size(); j++)
		{
			frames.push_back(new CZenFrame());
			int maptile = row.at(j);

			if(maptile==0)//food
			{		
				m_numberFood++;
				frames.at((i*(row.size()))+j)->AddObject(m_Food);
			}				
			else if (maptile==1)//wall
			{
				frames.at((i*(row.size()))+j)->AddObject(m_Wall);
			}	
			else if (maptile==2)//ghost
			{
				ghosts.push_back(new Ghost());

				if(twoPlayerMode && ghosts.size()==1)
					ghosts.at(ghosts.size()-1)->Init(ghosts.size(),&map,true, Keyboard);
				else
					ghosts.at(ghosts.size()-1)->Init(ghosts.size(),&map);
				ghosts.at(ghosts.size()-1)->SetPosition(j,0.5f,i);
				ghosts.at(ghosts.size()-1)->SetMap(&map);
					
				frames.at((i*(row.size()))+j)->AddObject(m_Floor);
			}
			else if (maptile==3)//pacman
			{
				if(m_iLevelNumber==1)
					m_pacman.Init(j,i);
				m_pacman.SetPosition(j, 0.0f, i);
				frames.at((i*(row.size()))+j)->AddObject(m_Floor);
				this->m_StartX = j;
				this->m_StartY = i;
			}
			else if (maptile==4)//portal
			{
				frames.at((i*(row.size()))+j)->AddObject(m_Teleporter);
			}
			else if (maptile==6)
			{
				frames.at((i*(row.size()))+j)->AddObject(m_Cherry);
			}
			else if (maptile==7)//supersfere
			{
				frames.at((i*(row.size()))+j)->AddObject(m_SuperSfere);
			}	
			frames.at((i*(row.size()))+j)->SetPosition((float)(j),0.0f,(float)(i));
		}
	}
	
	//lights
	if (m_iLevelNumber==1)
	{
		m_Lights.Init(length,width);
		AddObject(pacOverheadLight);
		AddObject(pacInsideLight);
		AddFrame(m_Lights);
	}
	m_Lights.SetPosition(0,0,0);

	//Pacman's overhead point light
	pacOverheadLight.m_Light.Type = D3DLIGHT_SPOT;
	pacOverheadLight.m_Light.Theta=D3DX_PI/8;
	pacOverheadLight.m_Light.Phi=D3DX_PI/8;
	pacOverheadLight.m_Light.Direction=D3DXVECTOR3(0, -1.0f, 0);
	pacOverheadLight.m_Light.Attenuation0=1;
	pacOverheadLight.m_Light.Range = 8;
	pacOverheadLight.SetDiffuse(1,0,0);
	pacOverheadLight.Enable(true);
	


	pacInsideLight.m_Light.Type = D3DLIGHT_POINT;
	pacInsideLight.m_Light.Range = 2;
	pacInsideLight.SetDiffuse(1,0,0);
	pacInsideLight.Enable(true);


	initialLighting = true;

	if (m_iLevelNumber==1)
		m_InitLight.Init(width,length,m_StartX,m_StartY, true);
	else 	m_InitLight.Init(width,length,m_StartX,m_StartY);
	m_Lights.blue.SetDiffuse(0,0,0);
	m_Lights.yellow.SetDiffuse(0,0,0);
	m_Lights.white.SetDiffuse(0,0,0);
	m_Lights.magenta.SetDiffuse(0,0,0);
	m_Lights.cyan.SetDiffuse(0,0,0);
	m_Lights.red.SetDiffuse(0,0,0);
				
	counterLight=0;
	return S_OK;
}

HRESULT GameFieldFrame::Render()
{
if(m_InitLight.animation){
	fppMode=true;

	for(unsigned int i = 0; i < frames.size(); i++)
	{
		frames[i]->Render();
	}
	for(unsigned int i = 0; i < ghosts.size(); i++)
			ghosts[i]->Render();
	m_pacman.Render();
		m_Lights.blue.SetDiffuse(0,0,0);
	m_Lights.yellow.SetDiffuse(0,0,0);
	m_Lights.white.SetDiffuse(0,0,0);
	m_Lights.magenta.SetDiffuse(0,0,0);
	m_Lights.cyan.SetDiffuse(0,0,0);
	m_Lights.red.SetDiffuse(0,0,0);
	m_Lights.Render();

	m_InitLight.Render();
		
		}else{
			if(fppMode==true){
					if(wolfenstein3dMode==true)
							{
								float temp_x, temp_y, temp_z;
								m_pacman.m_Frame2.GetPosition(temp_x, temp_z, temp_y);
								m_Camera->SetPosition( temp_x, 0.6, temp_y-0.5);
								m_Camera->SetLookPoint(temp_x,0.5f,temp_y +10);
								m_Camera->Update();
							}
				fppMode=false;
				}

	for(unsigned int i = 0; i < frames.size(); i++)
	{
		frames[i]->Render();
	}
		for(unsigned int i = 0; i < ghosts.size(); i++)
			ghosts[i]->Render();
		if(wolfenstein3dMode)
		{	
			m_pacman.Update();	
			m_pacman.Update();	
			m_pacman.Update();
		}else
			m_pacman.Render();

			if(counterLight<LIGHTING_POINT_INTRO_LENGTH)
				{
				counterLight++;
					m_Lights.blue.SetDiffuse(0.6*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.8*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.5*counterLight/LIGHTING_POINT_INTRO_LENGTH);
					m_Lights.yellow.SetDiffuse(0.6*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.8*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.5*counterLight/LIGHTING_POINT_INTRO_LENGTH);
					m_Lights.white.SetDiffuse(0.6*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.8*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.5*counterLight/LIGHTING_POINT_INTRO_LENGTH);
					m_Lights.magenta.SetDiffuse(0.6*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.8*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.5*counterLight/LIGHTING_POINT_INTRO_LENGTH);
					m_Lights.cyan.SetDiffuse(0.6*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.8*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.5*counterLight/LIGHTING_POINT_INTRO_LENGTH);
					m_Lights.red.SetDiffuse(0.6*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.8*counterLight/LIGHTING_POINT_INTRO_LENGTH,0.5*counterLight/LIGHTING_POINT_INTRO_LENGTH);
				
				}

			m_Lights.Render();


	RadarMapRender();

		}
		float x,y,z;
	m_pacman.m_Frame1.GetPosition(x,y,z);

	pacInsideLight.SetPosition(x,0,z);
	pacInsideLight.Render();
	pacOverheadLight.SetPosition(x,5,z);
	pacOverheadLight.Render();

	return S_OK;
}

void GameFieldFrame::SetMap()
{
	m_numberFood = 0;
	frames.clear();
	//create the frames from the map
	for (unsigned int i = 0; i < map.size(); i++)
	{
		row = map.at(i);
		for(unsigned int j = 0; j < row.size(); j++)
		{
			frames.push_back(new CZenFrame());
			int maptile = row.at(j);

			if(maptile==0)
			{				
				frames.at((i*(row.size()))+j)->AddObject(m_Food);
				m_numberFood++;
			}				
			else if (maptile==1)
			{
				frames.at((i*(row.size()))+j)->AddObject(m_Wall);
			}	
			else if (maptile==2)
			{
				frames.at((i*(row.size()))+j)->AddObject(m_Floor);
			}
			else if (maptile==3)
			{
				frames.at((i*(row.size()))+j)->AddObject(m_Floor);
			}			
			else if (maptile==4)
			{
				frames.at((i*(row.size()))+j)->AddObject(m_Teleporter);
			}
			else if (maptile==5)
			{
				frames.at((i*(row.size()))+j)->AddObject(m_Floor);
			}	
			else if (maptile==6)
			{
				frames.at((i*(row.size()))+j)->AddObject(m_Cherry);
			}
			else if (maptile==7)
			{
				frames.at((i*(row.size()))+j)->AddObject(m_SuperSfere);
			}
			frames.at((i*(row.size()))+j)->SetPosition((float)(j),0.0f,(float)(i));
		}
	}
}


int GameFieldFrame::GetWidth()

{
	return width;
}

int GameFieldFrame::GetLength()
{
	return length;
}
void GameFieldFrame::GhostsAI()
{
	float x,y,z;
	m_pacman.m_Frame1.GetPosition(x,y,z);
	for(int i=0;i<ghosts.size();i++)
		ghosts[i]->ThinkAndMove(m_pacman.m_eatGhost,(int)x,(int)z);
	}
void GameFieldFrame::RadarMapRender()
	{

		
		if(wolfenstein3dMode || macieksbool )
			{

			int y = map.size();
			int x = map.at(0).size();
			D3DRECT rect;
			rect.x1=0;
			rect.x2=RADARMAP_SIZE_X*x;
			rect.y1=0;
			rect.y2=y*RADARMAP_SIZE_Y;
			zen->Rectangle32Fast(&rect,D3DCOLOR_ARGB(0,110,145,155),zen->m_pDevice);
			for(int e =0;e<map.size();e++){
				int u = map.size();
				
				for(int a=0;a<map.at(u-1-e).size();a++){

					D3DRECT rect;
					rect.x1=0+RADARMAP_SIZE_X*a;
					rect.x2=RADARMAP_SIZE_X+RADARMAP_SIZE_X*a;
					rect.y1=0+RADARMAP_SIZE_Y*(u-1-e);
					rect.y2=RADARMAP_SIZE_Y+RADARMAP_SIZE_Y*(u-1-e);
					if(map.at(e).at(a)==1)
					zen->Rectangle32Fast(&rect,D3DCOLOR_ARGB(255,110,245,5),zen->m_pDevice);
					if(map.at(e).at(a)==2)
					zen->Rectangle32Fast(&rect,D3DCOLOR_ARGB(255,0,0,40),zen->m_pDevice);
					
					if(map.at(e).at(a)==3)
					zen->Rectangle32Fast(&rect,D3DCOLOR_ARGB(255,255,255,115),zen->m_pDevice);
					
					}
				}

			}

	}

void GameFieldFrame::SetZenEngine(CZenEngine* zen)
{
	this->zen = zen;
}

void GameFieldFrame::SetMapAtPosition(int a, int b)
{
	int length = GetLength();
	delete frames.at((b*(length))+a);
	frames.at(((b)*(length))+a)=	new CZenFrame();

	int maptile = map.at(b).at(a);
	if(maptile==0)
	{				
		frames.at((b*(length))+a)->AddObject(m_Food);
	}				
	else if (maptile==1)
	{
		frames.at((b*(length))+a)->AddObject(m_Wall);
	}	
	else if (maptile==2)
	{
		frames.at((b*(length))+a)->AddObject(m_Floor);
	}
	else if (maptile==3)
	{
		frames.at((b*(length))+a)->AddObject(m_Floor);
	}
	else if (maptile==4)
	{
		frames.at((b*(length))+a)->AddObject(m_Teleporter);
	}
	else if (maptile==5)
	{
		frames.at((b*(length))+a)->AddObject(m_Floor);
	}
	frames.at((b*length)+a)->SetPosition((float)(a),0.0f,(float)(b));

	return;
}
void GameFieldFrame::ResetGhosts()
{
	for(int i = 0; i < ghosts.size(); i++)
	{
		ghosts.at(i)->Reset();
	}
}
void GameFieldFrame::SetZenSound(CZenSound * sound){
	m_Sound = sound;
	
	}
void GameFieldFrame::SetZenCamera(CZenCamera * camera){
	m_Camera = camera;
	
	}